P3121 [USACO15FEB]Censoring G
这道题很明显是一道AC自动机的题目。
可以先将AC自动机板子打出来,打出来后该如何做这到题?可以考虑暴力做法,一个while循环一直扫描,每次扫描到了直接删除,但很明显,这样是会超时的。
通过标签观察我们发现,重新出现的单词是跟前面的部分没有关系的,那么我们就可以用栈来维护,一个栈来维护没有被删除的字符,另一个栈来维护AC自动机的下标
代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e6 + 5, INF = 0x3f3f3f3f;

char str[N], s[N];
int tr[N][26], idx, cnt[N], net[N], len[N];
int stk1[N], stk2[N], top;
queue<int> q;

void insert()
{
int p = 0;
for (int i = 0; str[i]; i++)
{
int t = str[i] - 'a';
if (!tr[p][t])
tr[p][t] = ++idx;
p = tr[p][t];
}
cnt[p] = strlen(str);
}

void build()
{
for (int i = 0; i < 26; i++)
if (tr[0][i])
q.push(tr[0][i]);
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = 0; i < 26; i++)
{
int p = tr[t][i];
if (!p)
tr[t][i] = tr[net[t]][i];
else
{
net[p] = tr[net[t]][i];
q.push(p);
}
}
}
}

int main()
{
scanf("%s", &s);
int n = 1;
for (int i = 1; i <= n; i++)
{
scanf("%s", &str);
insert();
}
build();
for (int i = 0, j = 0; s[i]; i++)
{
int t = s[i] - 'a';
j = tr[j][t];
stk1[++top] = t;
stk2[top] = j;
if (cnt[j])
{
top -= cnt[j];
if (!top)
j = 0;
else
j = stk2[top];
}
}
for (int i = 1; i <= top; i++)
printf("%c", stk1[i] + 'a');
return 0;
}